/**
 * 
 */
package de.fsujena.chat_pi.server;

import java.io.IOException;
import java.util.Date;

import de.fsujena.chat_pi.message.SysMessage;
import de.fsujena.chat_pi.message.SysMessage.MESSAGE;
import de.fsujena.chat_pi.message.SysMessage.CATEGORY;
import de.fsujena.chat_pi.user.User;

/**
 * @author Erik Hebestreit
 *
 */
public class SysMessageHandler {
	
	SysMessage message = null;
	
	MessageListener msgListener;

	/**
	 * Constructor.
	 */
	public SysMessageHandler(MessageListener msgListener) {
		this.msgListener = msgListener;
	}
	
	public boolean handleSysMessage(SysMessage message) {
		this.message = message;
		return filterCategory();		
	}

	/**
	 * process the received message and call the appropriate methods
	 * @return
	 */
	private boolean filterCategory() {
		switch (message.getCategory()) {					//filter message type
		case CONNECTION:
			switch (message.getMessage()){					//filter message
			case DISCONNECTED:
				//msgListener.distributeMsg(message);
				msgListener.close(false);
				break;
			default:
				break;
			}
			break;
		case LOGIN:
			switch (message.getMessage()){
			case WANT_TO_LOGIN:								
				if (msgListener.loggedIn) {
					msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.ALREADY_LOGGED_IN);
					}else{
						return userLogin();
				}
				break;
			case LOGGED_OUT:
					msgListener.logout();
					break;
			default:
				break;
			}
			break;
			
		case REGISTRATION:
			switch(message.getMessage()){
			case WANT_TO_REGISTER:
				return register();
			case REMOVE_ME:								//user wants to removes himself from the list
				int userNum = msgListener.serverObject.networkListener.userExists(message.getSenderUsername());			//get the index of the user in the list
				if (userNum >= 0) {																						//verify that the user exists
					msgListener.serverObject.networkListener.messageListener.get(userNum).sendSysMessage(CATEGORY.STATUS, MESSAGE.YOU_ARE_REMOVED);//tell him that he going to be removed
					msgListener.serverObject.networkListener.removeClient(message.getSenderUsername());					//close connection
				}
				
				msgListener.serverObject.userManager.removeUser(message.getSenderUsername());							//remove user from list
				break;
				
			default:
				break;
			}
			break;
			
		case CHANGE_USERNAME:
			if (message.getMessage() == MESSAGE.WANT_TO_CHANGE_USERNAME) {
				return changeUsername();
			}
			break;
			
		case CHANGE_PASSWORD:
			if (message.getMessage() == MESSAGE.WANT_TO_CHANGE_PASSWORD) {
				return changePassword();
			}
			break;
			
		case STATUS:
			switch (message.getMessage()) {
			case REQUEST_USER_LIST:
				msgListener.sendUserList();
				break;
			case REQUEST_ADMIN_LIST:
				msgListener.sendSysMessage(CATEGORY.STATUS, MESSAGE.SEND_ADMIN_LIST, null,msgListener.serverObject.userManager.adminlist() );
				break;
			case REQUEST_MOD_LIST:
				msgListener.sendSysMessage(CATEGORY.STATUS, MESSAGE.SEND_MOD_LIST, null,msgListener.serverObject.userManager.modlist() );
				break;
			case REQUEST_ROLE:
				msgListener.sendSysMessage(CATEGORY.STATUS,MESSAGE.SEND_ROLE,null,msgListener.serverObject.userManager.checkUserRole(msgListener.username));
				break;
			default:
				break;
			}
			break;
			
		case ADMIN:
			if (msgListener.serverObject.userManager.checkUserRole(msgListener.username) != User.ROLE.ADMIN) {
				msgListener.sendSysMessage(CATEGORY.STATUS, MESSAGE.NO_ADMIN);
				break;
			}
			
			switch (message.getMessage()) {
			case REMOVE_USER:
				int userNum = msgListener.serverObject.networkListener.userExists(message.getMessageString());
				if (userNum >= 0) {
					msgListener.serverObject.networkListener.messageListener.get(userNum).sendSysMessage(CATEGORY.STATUS, MESSAGE.YOU_ARE_REMOVED);
					msgListener.serverObject.networkListener.removeClient(message.getMessageString());
				}
				
				msgListener.serverObject.userManager.removeUser(message.getMessageString());
				break;

			default:
				break;
			}
			
			break;
			
		case MODERATE:
			if (msgListener.serverObject.userManager.checkUserRole(msgListener.username) != User.ROLE.MODERATOR && msgListener.serverObject.userManager.checkUserRole(msgListener.username) != User.ROLE.ADMIN) {
				msgListener.sendSysMessage(CATEGORY.STATUS, MESSAGE.NO_MOD);
				break;
			}
			
			int userNum;
			
			switch (message.getMessage()) {
			case BANN_USER:
				userNum = msgListener.serverObject.networkListener.userExists(message.getMessageString());
				if (userNum >= 0) {
					msgListener.distributeMsg(message);
					try {
						msgListener.connector.sendMessageObject(message);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					msgListener.serverObject.networkListener.removeClient(message.getMessageString());
				}
				
				msgListener.serverObject.userManager.bannUser(message.getMessageString());
				break;
				
			case KICK_USER:
				userNum = msgListener.serverObject.networkListener.userExists(message.getMessageString());
				if (userNum >= 0) {
					msgListener.distributeMsg(message);
					try {
						msgListener.connector.sendMessageObject(message);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					msgListener.serverObject.networkListener.removeClient(message.getMessageString());
				}
				break;
				
			case UNBANN_USER:
				msgListener.serverObject.userManager.unbannUser(message.getMessageString());
				break;

			default:
				break;
			}

		default:
			break;
		}
		
		return false;
		
	}

	/**
	 * changes the password of an registered user
	 * 
	 * @return true if successful
	 */
	private boolean changePassword() {
		Object inputObject;
		String user = null, new_password = null, password = null;
		SysMessage sysMessage;
		
		try {
			msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.REQUEST_USERNAME);
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_USERNAME){
					user = sysMessage.getMessageString();
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (!msgListener.serverObject.userManager.checkUserExists(user)) {
				//TODO check if user is already logged in
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.USERNAME_UNKNOWN);
				return false;
			}
			
			if (msgListener.serverObject.userManager.users.get(user).status != User.STATUS.NORMAL) {
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.USERNAME_BANNED);
				return false;
			}
			
			msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.REQUEST_PASSWORD);							
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_PASSWORD){
					password = sysMessage.getMessageString();			
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (!msgListener.serverObject.userManager.checkUserPassword(user, password)) {
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.PASSWORD_WRONG);
				return false;
			}
			
			msgListener.sendSysMessage(CATEGORY.CHANGE_PASSWORD, MESSAGE.REQUEST_CHANGED_PASSWORD);				//now request the changed password
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_CHANGED_PASSWORD){
					new_password = sysMessage.getMessageString();
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			msgListener.serverObject.userManager.users.get(user).setPassword(password, new_password);
			
			msgListener.serverObject.userManager.saveUserMap();													//saves the changes
			msgListener.sendSysMessage(CATEGORY.CHANGE_PASSWORD, MESSAGE.PASSWORD_CHANGED,new_password);		//tell the client that the passwordchange was successful
			
			return true;
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * changes the username of an user
	 * @return true if successful
	 */
	private boolean changeUsername() {
		Object inputObject;
		String user = null, new_user = null, password = null;
		SysMessage sysMessage;
		
		try {
			msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.REQUEST_USERNAME);
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_USERNAME){
					user = sysMessage.getMessageString();
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (!msgListener.serverObject.userManager.checkUserExists(user)) {
				//TODO check if user is already logged in
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.USERNAME_UNKNOWN);
				return false;
			}
			
			if (msgListener.serverObject.userManager.users.get(user).status != User.STATUS.NORMAL) {
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.USERNAME_BANNED);
				return false;
			}
			
			msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.REQUEST_PASSWORD);					
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_PASSWORD){
					password = sysMessage.getMessageString();
					System.out.println(password);
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (!msgListener.serverObject.userManager.checkUserPassword(user, password)) {
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.PASSWORD_WRONG);
				return false;
			}
			
			msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.REQUEST_CHANGED_USERNAME);
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_CHANGED_USERNAME){
					new_user = sysMessage.getMessageString();
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (msgListener.serverObject.userManager.checkUserExists(new_user)) {
				msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.USERNAME_ALREADY_EXISTS);
				return false;
			}
			
			msgListener.serverObject.userManager.users.get(user).name = new_user;
			msgListener.serverObject.userManager.users.put(new_user, msgListener.serverObject.userManager.users.get(user));
			msgListener.serverObject.userManager.users.remove(user);
			
			msgListener.serverObject.userManager.saveUserMap();													//saves the changes
			msgListener.username=new_user;																		//changes the username of the massagelistener
			msgListener.sendSysMessage(CATEGORY.CHANGE_USERNAME, MESSAGE.USERNAME_CHANGED,new_user);			//tell the client that the namechange was successful
			SysMessage sysMsg = new SysMessage(CATEGORY.CHANGE_USERNAME,MESSAGE.USERNAME_CHANGED, new_user);	
			sysMsg.setSent(new Date());
			sysMsg.setSenderUsername(user);																		//tells which user changed his name
			msgListener.distributeMsg(sysMsg);																	//tell the other clients that a user changed his name
			
			
			return true;
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * register an new user on the server
	 * @return true if successful
	 */
	private boolean register() {
		Object inputObject;
		String user = null, password = null;
		
		msgListener.sendSysMessage(CATEGORY.REGISTRATION, MESSAGE.REQUEST_NEW_USERNAME);
		
		try {
			inputObject = msgListener.connector.readGeneralObject();
		
		
			SysMessage sysMessage;
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_NEW_USERNAME){
					user = sysMessage.getMessageString();
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (msgListener.serverObject.userManager.checkUserExists(user)) {
				msgListener.sendSysMessage(CATEGORY.REGISTRATION, MESSAGE.USERNAME_ALREADY_EXISTS);
				return false;
			}
			
			
			msgListener.sendSysMessage(CATEGORY.REGISTRATION, MESSAGE.REQUEST_NEW_PASSWORD);
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_NEW_PASSWORD){
					password = sysMessage.getMessageString();			
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			msgListener.serverObject.userManager.createUser(user, password);
			
			msgListener.sendSysMessage(CATEGORY.REGISTRATION,MESSAGE.REGISTRATION_SUCCESSFUL);
			
			msgListener.serverObject.postInfo(String.format("%s registered at the server", user));
			return true;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return false;
	}

	/**
	 * login an user
	 * @return true if successful
	 */
	private boolean userLogin() {
		Object inputObject;
		String user = null, password = null;
		
		msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.REQUEST_USERNAME);
		
		try {
			inputObject = msgListener.connector.readGeneralObject();
		
		
			SysMessage sysMessage;
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_USERNAME){
					user = sysMessage.getMessageString();
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (!msgListener.serverObject.userManager.checkUserExists(user)) {
				//TODO check if user is already logged in
				msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.USERNAME_UNKNOWN);
				return false;
			}
			
			if (msgListener.serverObject.userManager.users.get(user).status != User.STATUS.NORMAL) {
				msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.USERNAME_BANNED);
				return false;
			}
			
			if (msgListener.serverObject.networkListener.userLoggedIn(user)) {
				msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.ALREADY_LOGGED_IN);
				return false;
			}
						
			msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.REQUEST_PASSWORD);
			
			inputObject = msgListener.connector.readGeneralObject();
			
			if (inputObject instanceof SysMessage) {
				sysMessage = (SysMessage) inputObject;
				if (sysMessage.getMessage() == MESSAGE.SEND_PASSWORD){
					password = sysMessage.getMessageString();			
				} else {
					msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.MSG_NOT_EXPECTED);
					return false;
				}
			} else {
				msgListener.sendSysMessage(CATEGORY.ERROR, MESSAGE.WRONG_MSG_TYPE);
				return false;
			}
			
			if (!msgListener.serverObject.userManager.checkUserPassword(user, password)) {
				msgListener.sendSysMessage(CATEGORY.LOGIN, MESSAGE.PASSWORD_WRONG);
				return false;
			} else {
				
				msgListener.sendSysMessage(CATEGORY.LOGIN,MESSAGE.LOGGED_IN);
				
				msgListener.username = user;
				msgListener.loggedIn = true;
				
				SysMessage newUserMessage = new SysMessage(CATEGORY.STATUS, MESSAGE.NEW_USER_INFO, user);
				msgListener.distributeMsg(newUserMessage);
				
				msgListener.serverObject.postInfo(String.format("%s connected to the server", msgListener.username));
				return true;
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}
}
